package com.apanal.qlife.common.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.apanal.qlife.common.cache.BaseCacheAspect;
import com.apanal.qlife.sys.model.User;

/**
 * 用户授权缓存切面类
 * 
 * 
 * @author shuliangxing
 * 
 * @date 2015-9-30下午5:13:08
 */
@Component
@Aspect
public class UserAuthCacheAspect extends BaseCacheAspect {

	/**
	 * 设置缓存名称
	 */
	public UserAuthCacheAspect() {
		setCacheName("sys-authCache");
	}

	// 角色缓存key前缀
	private String rolesKeyPrefix = "roles-";

	// 权限缓存key前缀
	private String permissionsKeyPrefix = "permissions-";

	@Autowired
	private ResourceMenuCacheAspect resourceMenuCacheAspect;

	/**
	 * 角色目标类切点
	 */
	@Pointcut(value = "target(com.apanal.qlife.sys.service.RoleService)")
	public void roleServicePointcut() {
	}

	/**
	 * 资源目标类切点
	 */
	@Pointcut(value = "target(com.apanal.qlife.sys.service.ResourceService)")
	public void resourceServicePointcut() {
	}

	/**
	 * 群组目标类切点
	 */
	@Pointcut(value = "target(com.apanal.qlife.sys.service.GroupService)")
	public void groupServicePointcut() {
	}

	/**
	 * 增、删、改切点
	 */
	@Pointcut(value = "execution(* insert*(..)) || execution(* update*(..)) || execution(* delete*(..))")
	public void authCacheEvictAllPointcut() {
	}

	/**
	 * 角色查询切点
	 */
	@Pointcut(value = "execution(* findNamesByUser(*)) && args(arg)", argNames = "arg")
	public void roleAuthCacheablePointcut(User arg) {
	}

	/**
	 * 资源查询切点
	 */
	@Pointcut(value = "execution(* findPermissionsByUser(*)) && args(arg)", argNames = "arg")
	public void resourceAuthCacheablePointcut(User arg) {
	}

	/**
	 * 增、删、改前置通知
	 * 
	 * @throws Throwable
	 */
	@Before(value = "(roleServicePointcut() || resourceServicePointcut() || groupServicePointcut()) && authCacheEvictAllPointcut()")
	public void authCacheEvictBeforeAdvice() throws Throwable {
		clear();
	}

	/**
	 * 缓存或使用缓存环绕通知
	 * 
	 * @param pjp
	 * @param arg
	 * @return
	 * @throws Throwable
	 */
	@Around(value = "(roleServicePointcut() && roleAuthCacheablePointcut(arg)) || (resourceServicePointcut() && resourceAuthCacheablePointcut(arg))", argNames = "pjp,arg")
	public Object authCacheableAroundAdvice(ProceedingJoinPoint pjp, User arg)
			throws Throwable {
		User user = arg;

		String methodName = pjp.getSignature().getName();
		String key = "";
		if ("findNamesByUser".equals(methodName)) {
			key = rolesKey(user.getUseId());
		} else if ("findPermissionsByUser".equals(methodName)) {
			key = permissionsKey(user.getUseId());
		}

		Object retVal = get(key);

		if (retVal != null) {
			log.debug("cacheName:{}, hit key:{}", cacheName, key);
			return retVal;
		}
		log.debug("cacheName:{}, miss key:{}", cacheName, key);

		retVal = pjp.proceed();

		put(key, retVal);

		return retVal;
	}

	/**
	 * 根据用户id移除缓存内容
	 * 
	 * @param userId
	 */
	public void evict(Long userId) {
		evict(rolesKey(userId));
		evict(permissionsKey(userId));

		// 当权限过期时同时清理菜单缓存
		resourceMenuCacheAspect.evict(userId);
	}

	/**
	 * 情况缓存
	 */
	@Override
	public void clear() {
		super.clear();
		// 当权限过期时同时清理菜单缓存
		resourceMenuCacheAspect.clear();
	}

	/**
	 * 根据用户id得到角色缓存key
	 * 
	 * @param userId
	 * @return
	 */
	private String rolesKey(Long userId) {
		return this.rolesKeyPrefix + userId;
	}

	/**
	 * 根据用户id得到权限缓存key
	 * 
	 * @param userId
	 * @return
	 */
	private String permissionsKey(Long userId) {
		return this.permissionsKeyPrefix + userId;
	}

}
